home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / lisp / elk-2_0.lha / elk-2.0 / doc / paper / paper.tr < prev    next >
Text File  |  1992-10-15  |  69KB  |  1,589 lines

  1. .\" .fp 1 PR
  2. .\" .fp 2 PI
  3. .\" .fp 3 PB
  4. .fp 5 C
  5. .de P
  6. .br
  7. .ne 3
  8. .sp .4
  9. .LP
  10. .ft 2
  11. ..
  12. .              \" Scheme code start
  13. .de Ss
  14. .KS
  15. .ta 8.5c
  16. .ft 5
  17. .ps -2
  18. .vs -2
  19. .nf
  20. .in 1c
  21. .sp .3c
  22. ..
  23. .              \" Scheme code end
  24. .de Se
  25. .ft
  26. .ps
  27. .vs
  28. .fi
  29. .in
  30. .KE
  31. .sp .5
  32. ..
  33. .              \" Newline in Scheme code
  34. .de Sl
  35. .sp .5
  36. ..
  37. .nr lS 0 1
  38. .              \" Listing start
  39. .de Ls
  40. .br
  41. .KF
  42. .sp .5
  43. .LP
  44. \l'\\n(.lu_'
  45. ..
  46. .              \" Listing caption:  .Lc caption
  47. .de Lc
  48. .sp .2
  49. .ce 999
  50. \f3\s-1Listing \\n+(lS:\fP  \c
  51. \\$1\s0
  52. .if !\(bs\\$2\(bs\(bs \s-1\&\\$2\s0
  53. .ce 0
  54. ..
  55. .              \" Listing end:  .Le reference
  56. .de Le
  57. .tm s/@L(\\$1)/\\n(lS/g
  58. .LP
  59. \l'\\n(.lu_'
  60. .sp
  61. .KE
  62. ..
  63. .              \" Notes start (at end of listing)
  64. .de Ns
  65. .sp
  66. .ps -2
  67. .vs -2
  68. .in 1c
  69. .ll -1c
  70. ..
  71. .              \" Notes end
  72. .de Ne
  73. .ll
  74. .in
  75. .vs
  76. .ps
  77. .sp -.3
  78. ..
  79. .ds E Elk
  80. .TL
  81. Elk: The Extension Language Kit
  82. .AU
  83. Oliver Laumann, Carsten Bormann
  84. .AI
  85. Technische Universit\*at Berlin, Germany
  86. .AB
  87. In the past, users generally were at the mercy of the authors of an
  88. application when it came to adapting it to their individual needs and
  89. tastes.
  90. Fitting an application with an \f2extension language\fP (or \f2embedded
  91. language\fP) enables users to customize and enhance it without having to
  92. modify its source code.
  93. Recently, variants of the programming language Lisp have become increasingly
  94. popular for this purpose, to the point where the abundance of different
  95. dialects has become a problem.
  96. Of the two standardized dialects of Lisp, only \f2Scheme\fP is suitably
  97. modest, yet sufficiently general, to serve as an extension language.
  98. .PP
  99. \f2Elk\fP, the \f2Extension Language Kit\fP, is a Scheme implementation
  100. that is intended to be used as a general, reusable extension language
  101. subsystem for integration into existing and future applications.
  102. Applications can define their own Scheme data types and primitives, which
  103. provide for a tightly-knit integration of the C/C++ parts of the application
  104. with Scheme code.
  105. Library interfaces such as those to various X Window System libraries
  106. show the effectiveness of this approach.
  107. Various features of Elk such as dynamic loading of object files and
  108. freezing of fully customized applications into executables
  109. (implemented in those UNIX environments where it was feasible)
  110. increase its usability as the backbone of a complex application.
  111. Elk has been used as such for nearly five years within a
  112. locally-developed ODA-based multimedia document editor; it has been
  113. used in numerous other projects after it could be made freely
  114. available three years ago.
  115. .AE
  116. .NH
  117. Introduction
  118. .PP
  119. The designers and implementors of a large or complex application can
  120. rarely anticipate all requirements future users will have on the
  121. application.
  122. Typically, users wish to be able to customize the user-interfaces
  123. of applications according to their personal tastes or requirements,
  124. or they have the desire to extend the functionality of an application
  125. (either by combining existing functions into new ones or by adding
  126. entirely new capabilities).
  127. This is especially true for daily-used applications such as text
  128. editors and for applications with a high degree of user-interaction
  129. or with complex graphical user-interfaces.
  130. .PP
  131. Any application can certainly be customized by modifying its source
  132. code and recompiling it.
  133. But this approach is often not feasible, as the source code of the
  134. application or the tools needed to recompile it may not be available.
  135. Even if it were feasible, it would be a time-consuming process;
  136. it would be hard to keep up with new releases of the application;
  137. and the coexistence of multiple, similar versions of the same
  138. application would be a general maintenance headache.
  139. .PP
  140. The alternative to this approach is to not ``hard-wire'' the entire
  141. functionality and all external aspects of an application in the source
  142. code at all, but to provide means to customize the application's
  143. behavior later by it's users.
  144. .P
  145. Early Customization and Extension Languages
  146. .PP
  147. Many applications support at least simple methods for customization,
  148. such as command line options or configuration files.
  149. More powerful tools for customization are \f2macro languages\fP,
  150. \f2command languages\fP, or \f2scripting languages\fP that are
  151. typically found in text editors and word processors.
  152. Prominent examples of such customization and extension languages
  153. are the macro language of the now legendary TECO editor and,
  154. in UNIX, the macro language of the \f2troff\fP text formatter
  155. [Ossanna 1979] and the configuration language of the \f2sendmail\fP
  156. program.
  157. .PP
  158. Although many of these classic extension languages are quite
  159. powerful (some of them are full-fledged programming languages),
  160. they have a reputation of being ``cryptic'' and hard to understand
  161. and use by untrained users.
  162. The prevailing opinion seems to be that only experts can actually
  163. benefit from these types of extension languages (for example,
  164. people who have mastered the \f2sendmail\fP configuration language
  165. in all details are commonly appointed the status of a ``guru'').
  166. In fact, it can be observed that only very few users of the \f2troff\fP
  167. text formatter (whose macro language is reputed to be particularly
  168. cryptic) are using macro packages written by themselves; many users
  169. give up after some time and fall back on vendor-supplied macro
  170. packages or packages written by a ``troff-guru''.
  171. .PP
  172. Experience also indicates that simplified or specialized extension
  173. languages often grow and have more features added until they resemble
  174. a full programming language.
  175. Such ``organically grown'' extension languages are likely to be
  176. contorted designs as they will consist of several levels of extensions
  177. glued on to their initial, more limited design.
  178. .P
  179. High-Level Extension Languages
  180. .PP
  181. Recently application designers have begun to abandon
  182. specialized and cryptic macro-style extension languages in
  183. favor of extension languages that resemble usual high-level
  184. programming languages, mainly languages with Algol/Pascal-style
  185. or Lisp-style syntax and semantics.
  186. Prominent examples of such high-level extension languages are
  187. TPU developed by DEC, the \f2Ness\fP language of the Andrew
  188. Toolkit [Hansen 1990], AutoDesk's CAD extension language (a dialect
  189. of Lisp), and \f2Emacs-Lisp\fP, the extension
  190. language of Richard Stallman's popular GNU Emacs editor
  191. [Stallman 1981, Lewis et al. 1990].
  192. .PP
  193. Emacs was the first wide-spread application to employ an
  194. already existing and widely used high-level programming
  195. language as its extension and customization language.
  196. Emacs-Lisp is a dynamically-scoped dialect of Lisp with additional
  197. functionality for text-editing oriented operations.
  198. The approach taken by Emacs has been tremendously successful;
  199. during the last years users of Emacs have contributed a wealth of
  200. extensions written in Emacs-Lisp.
  201. .P
  202. Elk as a General, Reusable Extension Language
  203. .PP
  204. Using Lisp or Lisp-style languages as extension languages
  205. seems to enjoy growing popularity; several applications besides
  206. Emacs now use dialects of Lisp as their extension language.
  207. This development has one disadvantage: the number of coexisting
  208. incompatible (but similar) extension languages is continually growing.
  209. Users have to learn a new language for each new application,
  210. and application writers keep implementing new extension language
  211. interpreters instead of reusing existing ones.
  212. .PP
  213. These problems can be solved by making available a general,
  214. reusable extension language implementation that application
  215. writers can include into their applications.
  216. The main objective of the \f2Elk\fP project was to develop such a
  217. generic extension language and make it freely available to
  218. encourage application writers to use it in their applications.
  219. .NH
  220. Overview of the Extension Language Kit
  221. .P
  222. The Evolution of Elk
  223. .PP
  224. The development of \*E began when we were searching for a suitable
  225. extension language implementation for ISOTEXT [Bormann et. al. 1988,
  226. Bormann 1991],
  227. an ODA-based document processing system with a graphical user-interface.
  228. ISOTEXT is almost entirely written in C++; its user-interface is
  229. based on the X window system [Scheifler et al. 1986]
  230. and the OSF/Motif widget set.
  231. Customizability and extensibility by means of a full extension language
  232. was a basic requirement on the design of ISOTEXT.
  233. .PP
  234. As we considered language design to be the domain of a
  235. ``selected few'', we decided to use an existing programming
  236. language as the basis for the extension language of ISOTEXT.
  237. This decision was also influenced by our desire to develop a
  238. general, reusable extension language implementation that is
  239. not hard-wired into one specific application.
  240. For a number of reasons an interpreted language seemed preferable:
  241. it should be possible to add extensions to or modify extensions in
  242. a running application without re-linking it;
  243. bugs in extensions should not crash the application;
  244. interpreted languages usually offer better debugging facilities;
  245. and implementing an interpreter generally requires less
  246. efforts than implementing a compiler.
  247. .PP
  248. From the beginning we favored Lisp or a dialect of Lisp
  249. as the basis for a general extension language.
  250. Most dialects of the Lisp family are ``small'', easy to implement,
  251. general-purpose languages with simple syntax and powerful semantics,
  252. and the suitability of Lisp as an extension language had already been
  253. demonstrated by several applications, among them GNU Emacs.
  254. Early in the project we considered to use Emacs-Lisp,
  255. but it appeared infeasible to isolate the Lisp-interpreter
  256. from the rest of Emacs.
  257. In addition, at the time we investigated Emacs-Lisp it was lacking
  258. several desirable language features, such as support for floating point
  259. and arbitrary precision numbers (\f2bignums\fP).
  260. We also considered to use MIT Scheme [MIT 1984], but due to the enormous
  261. size of its implementation it would have dominated the size of
  262. the application.
  263. .P
  264. Scheme as an Extension Language
  265. .PP
  266. As other implementations of Lisp or Lisp-like languages available at
  267. the time of our investigations did not meet our requirements, we
  268. finally decided to write an interpreter for the Lisp dialect Scheme
  269. [Clinger et al. 1991, Dybvig 1987, Springer et al. 1989,
  270. Abelson et al. 1985].
  271. This Scheme interpreter is the main component of the \*E package.
  272. Scheme is a simplified, ``cleaned-up'' dialect of Lisp with
  273. first-class procedures and static scoping rules.
  274. The Scheme language is based on only a few language features and
  275. semantic concepts; it consists of a small core if syntactic
  276. forms, a set of extended forms derived from them, and a number
  277. of standard procedures (\f2primitive\fP procedures) that operate
  278. on a rich set of types of objects (among them numbers, lists, vectors,
  279. symbols, characters, and strings).
  280. In 1991 Scheme became an IEEE standard [IEEE\|Std\|1178-1990]
  281. (the standard document, although only 50 pages long,
  282. includes the complete formal semantics of the language).
  283. .PP
  284. The standardization effort has increased the acceptance of Scheme;
  285. for instance, the Extension Language Working Group
  286. of the CAD Framework Initiative has recently selected Scheme as the
  287. extension language for future CAD applications [CFI 1991a, CFI 1991b].
  288. Among the established programming languages we consider Scheme the
  289. ideal candidate for a general extension language \-
  290. it is standardized; its semantics are
  291. well-defined; it has a simple syntax and is easy to implement; and it
  292. is sufficiently small to not dwarf the application to be extended.
  293. .P
  294. Extending the Extension Language
  295. .PP
  296. The implementation of an extension language must itself be
  297. extensible.
  298. To enable code written in such a language to manipulate
  299. objects or state of the application to be extended,
  300. the language's base set of primitive procedures and data types
  301. must be augmented by application-specific primitives and types.
  302. In fact, easy extensibility of the language has been the primary
  303. design consideration in the development of \*E (as opposed to
  304. performance or number of language features).
  305. To allow \*E programs to be expressive in the context of a given
  306. application, application writers are encouraged (and expected)
  307. to extend the language base of \*E by a rich set of
  308. application-specific data types and Scheme primitives to operate on
  309. objects of these types.
  310. Adding new types and primitives to \*E is an inexpensive operation;
  311. it is not uncommon for an application to define hundreds
  312. of application-specific Scheme primitives.
  313. .\"
  314. .\" implementation must fit well to `host language' (schreibt cabo...)
  315. .PP
  316. All primitive procedures of \*E are C or C++ functions.
  317. This is true for both built-in primitives (such as \f2car\fP and \f2cdr\fP)
  318. and primitives defined by extensions.
  319. From the Scheme programmers' point of view, primitives and types from the
  320. base set of the language are indistinguishable from application-specific
  321. primitives and types.
  322. Extensions ``register'' new primitives with the interpreter
  323. by supplying the name of the primitive along with a pointer
  324. to the function implementing the primitive and other information.
  325. New types are defined in a similar way.
  326. Registration of new primitives and types typically takes place at the
  327. time the interpreter is invoked or when a compiled extension is loaded
  328. into the running interpreter.
  329. .PP
  330. Another way to use the extension mechanisms of \*E is to provide
  331. interfaces to libraries, such as the C library or the libraries
  332. of the X window system (e.\|g.\& \f2Xlib\fP).
  333. \*E has no facility to directly import ``foreign'' functions
  334. (although such a facility could be written as an extension;
  335. in fact, this has been done at a company where \*E is used).
  336. Therefore, a small amount of code acting as ``glue'' between \*E and
  337. the library has to be written to make the contents of a library
  338. available to Scheme programmers.
  339. The main purpose of this interface code is to check the arguments
  340. supplied to the library functions, to convert Scheme objects
  341. into C types, and to convert the results of library functions back
  342. into Scheme objects.
  343. Library extensions often act as glue between the application
  344. to be extended and the libraries used by the application; they allow
  345. the application writers to abstract from the details of the
  346. libraries.
  347. Although it is useful to distinguish between \f2library\fP extensions 
  348. and extensions interfacing to \f2applications\fP, there is no
  349. technical difference \- in both cases a collection of types
  350. and functions is made available to the Scheme world.
  351. .P
  352. The Contents of the Extension Language Kit
  353. .PP
  354. The \*E distribution consists of the Scheme interpreter (the
  355. \f2interpreter kernel\fP) and a number of library extensions.
  356. These provide interfaces to the X11 ``Xlib'' (similar to
  357. ``CLX'' [CLX 1991] in its functionality, but implemented on top
  358. of Xlib), to the X11 toolkit intrinsics (``Xt'')
  359. and the Athena and OSF/Motif widget sets, and to a small number
  360. of functions of the C library.
  361. The X extensions are especially useful for application writers
  362. whose applications have graphical user-interfaces based on X;
  363. \*E enables them to write their user-interfaces or parts thereof
  364. in Scheme to achieve maximum customizability.
  365. .PP
  366. \*E can also be used as a free-standing Scheme implementation.
  367. In combination with the X extensions it is well-suited as a tool
  368. for interactively exploring X, for teaching X to beginners, and
  369. as a platform for rapid prototyping of X-based applications.
  370. .NH
  371. Using Elk in Applications
  372. .P
  373. Bringing Everything Together
  374. .PP
  375. In contrast to other extension language implementations
  376. (e.\|g.\& TCL [Ousterhout 1990]),
  377. \*E does not provide its functionality in the form of a library that is
  378. statically linked into an application to be extended.
  379. Instead, the object modules comprising the application
  380. and all required library extensions are dynamically linked with and
  381. loaded into the running Scheme interpreter.
  382. To accomplish this, the \f2load\fP primitive of \*E has been
  383. extended to load object files \- compiled extensions written
  384. in C or C++ \- besides files containing Scheme code.
  385. Dynamic loading enables applications to load less frequently
  386. used modules into the running program on demand; such an
  387. application is initially smaller than the equivalent statically
  388. linked application (where all modules must be combined into
  389. one large executable file).
  390. .PP
  391. Dynamic loading of object files is often used together with the
  392. \f2dump\fP primitive that creates an executable file from
  393. the running interpreter, similar to \f2unexec\fP of GNU Emacs or
  394. \f2dump\%lisp\fP in some Lisp systems.
  395. The \f2dump\fP primitive of \*E differs from existing, similar
  396. mechanisms in that the newly created executable, when called, starts at
  397. the point where \f2dump\fP was called in the original invocation (as
  398. opposed to the program's \f2main\fP entry point).
  399. Here the return value of \f2dump\fP is ``true'', while in the original
  400. invocation it returns ``false'' (not unlike the UNIX \f2fork\fP system
  401. call).
  402. .P
  403. Dynamic Loading and Dump in Cooperation
  404. .PP
  405. To generate a new instance of an application one would typically
  406. invoke the Scheme interpreter, load all object modules and all Scheme
  407. code required initially, perform all initializations that can survive a
  408. ``dump'', and finally dump an image of the running interpreter
  409. containing all the loaded code into a new executable on disk.
  410. The use of \f2dump\fP avoids time-consuming activities like
  411. loading of object files and other initializations on each startup.
  412. The dumped executable, when started, resumes after the call to
  413. \f2dump\fP; at this point one would perform the remaining,
  414. environment-dependent initializations and finally invokes the
  415. application's ``main program'' (e.\|g.\& enter the X toolkit's event
  416. processing main loop).
  417. Listing @L(dump) shows a (slightly simplified) Scheme program that
  418. generates and starts a new instance of an application.
  419. .Ls
  420. .Ss
  421. ;;; Load initially required object files and Scheme files of
  422. ;;; application and dump image into executable file.
  423. ;;; Dumped file enters application's main loop on startup.
  424. .Sl
  425. (load 'main.o)     ; initial object modules
  426. (load 'edit.o)
  427. (load 'x11.o)      ; (a library extension)
  428. \&...
  429. (load 'ui.scm)     ; initial Scheme files
  430. (load 'custom.scm)
  431. (load 'x11.scm)
  432. \&...
  433. (initialize-application)
  434. .Sl
  435. (if (dump 'a.out)
  436.     (begin                   ; dumped a.out starts execution here
  437.       (initialize-some-more)
  438.       (main-loop-of-application)
  439.       (exit)))
  440. .Sl
  441. ;; Original invocation gets here when dump is finished.  We're done.
  442. .Se
  443. .Lc "Scheme code to generate and start an application"
  444. .Ns
  445. \f2Note:\fP Filenames can be given as symbols (besides the usual string
  446. literals).
  447. A more meaningful name than a.out would probably be chosen in practice.
  448. .Ne
  449. .Le dump
  450. .PP
  451. On systems that do not support dynamic linking and loading of
  452. object files (such as older versions of UNIX System V)
  453. or where \f2dump\fP cannot be implemented,
  454. the interpreter kernel and the application and library extensions
  455. are linked statically and combined into one executable.
  456. .PP
  457. In any case, in an application using \*E, the control initially
  458. rests in the Scheme interpreter.
  459. The interpreter acts as ``main program'' of the application; it is the
  460. interpreter's \f2main()\fP function which is invoked on startup of
  461. the program.
  462. Therefore the first code to execute in an application is Scheme code;
  463. this Scheme code provides the shell functionality of the application
  464. (it is hence called \f2shell code\fP).
  465. The shell code may perform a few simple tasks, for instance, load a
  466. user-provided initialization file containing customization code for
  467. the application and then enter the application's main loop,
  468. or it may be as complex as in ISOTEXT, where the entire X-based
  469. user-interface is written in Scheme.
  470. .P
  471. Making Oneself Known to the Extension Language
  472. .PP
  473. The application, as it is linked with the extension language
  474. interpreter, has full access to all external functions and variables of
  475. the interpreter kernel.
  476. The interpreter, on the other hand, does not have any knowledge of the
  477. contents of dynamically linked and loaded object modules; all it
  478. sees of an object file being loaded is the file's symbol table.
  479. To obtain ``hooks'' into a newly loaded extension, the interpreter
  480. searches the symbol table of each object file being loaded for
  481. functions whose names start with the prefix ``init_'' 
  482. (\f2extension initialization functions\fP) and invokes these functions
  483. as they are encountered.
  484. Likewise, to support extensions written in C++, any C++ static
  485. constructors found in the symbol table are called.
  486. When linked statically, the interpreter must scan its own symbol
  487. table on startup to find and invoke the initializations functions.
  488. .PP
  489. Besides initializing private data of the modules being loaded,
  490. these initialization functions register with the interpreter
  491. the Scheme primitives and Scheme data types implemented by the extensions.
  492. To enable extensions to register new primitive procedures and types,
  493. the interpreter kernel exports two functions: \f2Define_Primitive()\fP
  494. to register a new Scheme primitive and \f2Define_Type()\fP to
  495. register a new type.
  496. .PP
  497. The arguments supplied to \f2Define_Primitive()\fP are a pointer to the
  498. function implementing the primitive procedure, the Scheme name of the
  499. primitive, the minimum and maximum number of arguments, and
  500. a symbol indicating the \f2calling discipline\fP of the primitive.
  501. Calling disciplines are: normal procedure with fixed number of
  502. arguments, such as \f2car\fP; procedure with variable argument list,
  503. such as \f2append\fP; and \f2special form\fP (variable number of
  504. unevaluated arguments).
  505. \f2Define_Type\fP is invoked with the Scheme name of the type, the size
  506. of the type's representation in C or C++, two functions implementing
  507. the \f2eqv?\fP and \f2equal?\fP predicates for objects of this type, a
  508. function that is called by the interpreter to print an object of the
  509. new type (the type's \f2print function\fP), and a function providing
  510. information about the type to the garbage collector.
  511. The return value of \f2Define_Type()\fP is a ``handle'' to the newly
  512. defined type (basically a small, unique integer); its main uses are to
  513. check the type of arguments supplied to primitive procedures and to
  514. instantiate objects of this type.
  515. .NH
  516. Notes on the Implementation
  517. .P
  518. Implementing Continuations
  519. .PP
  520. Finding a way to efficiently implement Scheme's \f2continuations\fP
  521. called for considerable efforts during the design phase of \*E.
  522. Continuations are a powerful language feature; they support the
  523. definition of arbitrary control structures such as non-local
  524. loop and procedure exits, \f2break\fP and \f2return\fP as in C,
  525. exception handling facilities, explicit backtracking, co-routines,
  526. or multitasking based on \f2engines\fP.
  527. .PP
  528. The primitive procedure
  529. .Ss
  530. \s+1(call-with-current-continuation \f2receiver\fP)\s0
  531. .Se
  532. packages up the current execution state of the program into
  533. an object (the \f2continuation\fP or \f2escape procedure\fP)
  534. and passes this object as an argument to \f2receiver\fP (which is
  535. a procedure of one argument).
  536. Continuations are first-class objects in Scheme; they are
  537. represented as procedures of one argument (not to be confused
  538. with the \f2receiver\fP procedure).
  539. Each time a continuation procedure is called with a value, 
  540. it causes this value to be returned as the result of the
  541. \f2call-with-current-continuation\fP expression which created this
  542. continuation.
  543. If the procedure \f2receiver\fP terminates normally (i.\|e.\& does
  544. not invoke the continuation given to it), the value
  545. returned by \f2call-with-current-continuation\fP is the return
  546. value of \f2receiver\fP.
  547. .PP
  548. As long as the use of a continuation is confined to the runtime
  549. of the \f2receiver\fP procedure, \f2call-with-current-continuation\fP
  550. is similar in its functionality to \f2catch/throw\fP in most
  551. Lisp dialects or \f2setjmp/longjmp\fP in C.
  552. However, continuations, like all procedures in Scheme, have
  553. indefinite extent; they can be stored in variables and called
  554. an arbitrary number of times, even after the \f2receiver\fP and
  555. the enclosing \f2call-with-current-continuation\fP have already
  556. terminated.
  557. Listing @L(call-cc) shows a program fragment where continuations
  558. are used to get back an arbitrary number of times into the middle
  559. of an expression whose computation has already been completed.
  560. While not particularly useful, this example demonstrates that
  561. continuations can be used to build control structures that
  562. cannot be implemented by means of less general language features like
  563. catch/throw or setjmp/longjmp in C.
  564. .Ls
  565. .Ss
  566. (define function
  567.   (lambda (n m)
  568.     (+ n (mark m)))                    ; return n+m
  569. .Sl
  570. (define get-back "uninitialized")
  571. .Sl
  572. (define mark                           ; identity function, but also
  573.   (lambda (value)                      ; assign current continuation
  574.     (call-with-current-continuation    ; to a global variable
  575.       (lambda (continuation)
  576.         (set! get-back continuation)
  577.         value))))
  578. .Sl
  579. .Sl
  580. (function 10 20)  \z\(->  30                 ; invoke function
  581. (get-back 5)  \z\(->  15                     ; resume with new value
  582. (get-back 0)  \z\(->  10                     ; ...once more
  583. .Se
  584. .Lc "Using continuations with unlimited extent"
  585. .Le call-cc
  586. .PP
  587. The different approaches that can be used in implementing
  588. continuations are intimately tied to the strategies used for
  589. interpreting the language itself.
  590. Scheme interpreters generally employ a lexical analyzer and parser
  591. \- the \f2reader\fP \- to read and parse the Scheme source code and
  592. produce an intermediate representation of the program.
  593. During this phase, symbols are collected in a global hash table
  594. (in Lisp jargon, the symbols are \f2interned\fP), and a tree
  595. structure representing the program's S-expressions is built up
  596. on the heap of the interpreter.
  597. The majority of interpreters compile this intermediate representation
  598. into an abstract machine language (such as \f2byte code\fP) in a
  599. second pass (in practice, these passes may be combined in one pass).
  600. The evaluator is then implemented as an abstract machine which interprets
  601. the low-level language; this machine \- usually a simple stack
  602. machine \- may even be implemented in hardware.
  603. .PP
  604. In an abstract machine implementation, the obvious approach to implement
  605. \f2call-with-current-continuation\fP is to package up the contents of
  606. the registers (program counter, stack pointer, etc.) and the current
  607. runtime stack of the abstract machine.
  608. As continuations have indefinite extent, it would not suffice to just
  609. capture the abstract machine's registers (as the C library function
  610. \f2setjmp\fP does for the real machine).
  611. To be able to continue the evaluation of procedures that have
  612. already returned and whose frames are therefore no longer on the stack,
  613. a continuation must also embody the contents of the abstract
  614. machine's stack at the time it is created.
  615. When a continuation is applied, the machine resumes the ``frozen''
  616. computation by restoring the saved registers and stack contents
  617. of the abstract machine.
  618. .PP
  619. This technique would not work in \*E, because at the time a
  620. continuation is created, arbitrary library functions may be
  621. active in addition to Scheme primitives.
  622. For instance, consider the extension interfacing \*E to the
  623. ``Xt'' toolkit intrinsics of the X window system.
  624. When using this extension, a typical scenario is that some Scheme
  625. procedure invokes the primitive that enters the toolkit's event
  626. dispatching main loop (\f2XtAppMainLoop()\fP). 
  627. When an event arrives (for example, a mouse button press event), 
  628. the toolkit's main loop invokes a callback function, which in turn
  629. calls a user-supplied Scheme procedure to be executed when a
  630. mouse button is pressed.
  631. This Scheme procedure might in turn invoke yet another function
  632. from the ``Xt'' library, and so on.
  633. A similar example would be a \f2qsort\fP or \f2ftw\fP extension to \*E,
  634. where the user-supplied function called by the \f2qsort()\fP or
  635. \f2ftw()\fP C library function would invoke a procedure written
  636. in Scheme.
  637. .PP
  638. The interpreter's thread of execution at any time apparently involves
  639. both Scheme primitives and library functions (such as
  640. \f2XtAppMainLoop()\fP and \f2qsort()\fP in the examples above) in an
  641. arbitrary combination.
  642. Therefore, a continuation must not only embody the execution
  643. state of the active Scheme procedures, but also that of the
  644. currently active library functions (such as local variables
  645. used by the library functions).
  646. In the approach followed by \*E, a continuation is created by capturing
  647. the machine's registers \- like \f2setjmp\fP in C does \- and the C
  648. runtime stack.
  649. When a continuation is applied later, the registers and the saved
  650. stack contents are copied back.
  651. Actually, we did not follow the usual ``abstract machine''
  652. technique in \*E at all; instead, the Scheme evaluator directly
  653. interprets the intermediate representation produced by the reader.
  654. In a sense, it is the ``real'' machine (the hardware on which \*E
  655. is executed) that plays the role of the abstract machine in
  656. implementations with byte-code compilation.
  657. .PP
  658. Although the abstract machine technique usually yields faster
  659. execution of Scheme code, the performance of \*E is comparable to
  660. that of existing interpreters employing the abstract machine approach,
  661. and the implementation of \*E is less complex than that of comparable
  662. interpreters using byte-code compilation.
  663. While the technique to implement continuations in \*E is not
  664. portable \- it is based on certain assumptions on the machine's stack
  665. layout and the C compiler and runtime environment \-
  666. implementations of the small machine-dependent part now exist for
  667. most major machine architectures.
  668. .P
  669. The Implementation of ``dump''
  670. .PP
  671. Continuations provide a natural basis for implementing the
  672. execution-state preserving semantics of the \f2dump\fP primitive.
  673. When called, \f2dump\fP invokes \f2call-with-current-continuation\fP
  674. (actually, since it is written in C, the interpreter's internal version
  675. of \f2call-with-current-continuation\fP).
  676. The real work is done in the \f2receiver\fP procedure; it stores the
  677. newly created continuation into a global variable, creates an
  678. executable file from the image of the running process, sets a
  679. global \f2was-dumped\fP flag to indicate that a dump has taken place,
  680. and finally returns ``false''.
  681. The return value of the \f2dump\fP primitive is the return value
  682. of this call to \f2call-with-current-continuation\fP, i.\|e.\&
  683. ``false'' if a dump has just been performed.
  684. .PP
  685. When the interpreter \- either the original program or a dumped
  686. executable \- is started, it examines the \f2was-dumped\fP flag
  687. as its very first action.
  688. If the flag is set, the running interpreter was started from a 
  689. dumped executable.
  690. In this case the interpreter immediately invokes with an argument of
  691. ``true'' the continuation that was saved away by a call to \f2dump\fP;
  692. this causes that call to \f2dump\fP to finish and return ``true'' to
  693. its caller.
  694. If, on the other hand, the \f2was-dumped\fP flag is not set (i.\|e.\&
  695. the running process was not started from a dumped image), the
  696. interpreter initializes and starts up as usual.
  697. .PP
  698. Before writing an image of the running process to disk, \f2dump\fP
  699. has to close all open Scheme file ports, as open file descriptors would
  700. not survive a \f2dump\fP \- they would no longer be valid in the
  701. dumped executable.
  702. Generally, this is true for all objects pointing to information
  703. maintained by the UNIX kernel, such as the current directory, the
  704. current signal dispositions, resource limits, or interval timers.
  705. Users and implementors of \*E extensions must be aware of this
  706. particular restriction.
  707. For instance, users of the X11 extensions have to make sure that,
  708. if \f2dump\fP is to be used, connections to X-displays are only
  709. established in the dumped invocation.
  710. .PP
  711. To be able create an executable from the running process, \f2dump\fP
  712. has to open and read the a.out file from which the running process was
  713. started (actually, if the system linker has been called to dynamically
  714. load object files, the output of the most recent invocation of the
  715. linker is used instead of the original a.out).
  716. The symbol table of the new executable is copied from the a.out file of
  717. the running program; in addition, the a.out header has to be read to
  718. obtain the length of the text segment and the start of the data segment
  719. of the running process.
  720. To do so, \f2dump\fP has to determine the filename of a.out file from
  721. which the process was started based on the information in \f2argv[0]\fP
  722. and in the PATH environment variable.
  723. This approach is obviously based on several prerequisites: \f2dump\fP
  724. must be able to access its a.out file (\f2argv[0]\fP must carry
  725. meaningful information; the file must be readable) and the running
  726. program's a.out file must not have been stripped.
  727. It would have been advantageous for the implementation of \f2dump\fP
  728. if the entire a.out file had been automatically mapped into memory
  729. on startup, like it is done, for instance, in NEXT-OS/Mach.
  730. .PP
  731. \f2dump\fP combines the data segment and the ``bss'' segment of the
  732. running process into the data segment of the new executable.
  733. If \*E had a separate heap for storing constant objects (future
  734. versions may have one),
  735. \f2dump\fP would place this read-only part of the memory into the new
  736. executable's text segment to make it sharable.
  737. When the interpreter's heap is written to disk, \f2dump\fP seeks
  738. over the unused portions of the heap, so that fake blocks can be
  739. used for these parts of the file.
  740. This results in a considerable conservation of disk space in
  741. the final executable, as at least half of the interpreter's
  742. heap is unused at any time due to the garbage collection
  743. algorithm of \*E.
  744. .PP
  745. Since the a.out formats used in the numerous
  746. versions of UNIX differ vastly, \*E has to include separate
  747. implementations of \f2dump\fP for the currently supported
  748. a.out formats.
  749. Version 1.5 of \*E handles the BSD-style a.out format used
  750. in BSD and ``derived'' UNIX versions (such as SunOS 4.1),
  751. the COFF a.out format (used in older releases of UNIX System V
  752. and in A/UX),
  753. Extended COFF of MIPS-based computers running Ultrix, and
  754. the ELF a.out format of System V Release 4 and related UNIX
  755. versions (Solaris 2.0).
  756. .\"
  757. .\" stack alignment problem (alloca in main)
  758. .P
  759. Dynamic Loading of Object Files
  760. .PP
  761. When loading an object file during runtime, addresses
  762. within this object file must be relocated to its new location
  763. in the program's address space.
  764. To allow extensions to directly reference objects of the interpreter
  765. kernel, such as the heap and the built-in primitives, unresolved
  766. references into the \f2base program\fP must be resolved during
  767. dynamic loading.
  768. Finally, the object file needs to be able to export its entry points
  769. (such as \*E's extension initialization functions) to the base program.
  770. .PP
  771. More than one object file may have to be loaded into one invocation
  772. of \*E.
  773. To manage non-trivial, hierarchically structured sets of extensions,
  774. where a number of high-level extensions require one or more lower-level
  775. extensions to be loaded, it is essential that object files loaded later
  776. can make use of the symbols defined by previously loaded object files.
  777. As this style of dynamic loading allows building complex systems from
  778. small components incrementally, we will use the term \f2incremental
  779. loading\fP.
  780. .PP
  781. With the advent of 4.0\|BSD in 1980 [Joy 1980],
  782. support for incremental
  783. loading was added to the system linker and has since been supported by
  784. most major UNIX variants:
  785. when the -A option and the name of the base executable are supplied to the
  786. linker, linking is performed in a way that the object file produced by
  787. the linker can be read into the already running executable.
  788. The symbol table of the resulting object file is a combination of the
  789. symbols defined by the base program and the newly defined symbols added
  790. by the linking process, from the object file or from libraries used in
  791. linking.
  792. Only this newly linked code and data is entered into the
  793. resulting object file.
  794. The incremental style of dynamic loading is achieved by saving
  795. the resulting output file each time the linker is invoked and using
  796. this file as the base program for the next incremental loading step,
  797. such that both old and new symbols can be referenced.
  798. .PP
  799. Incremental loading is generally supported by the linkers of UNIX
  800. versions that use the BSD-style a.out format and by those of several
  801. UNIX systems based on more modern a.out formats (e.\|g.\& Ultrix).
  802. It is not supported by any existing release of UNIX System V.
  803. Some newer UNIX versions that have shared libraries and dynamic linking
  804. (such as System V Release 4 or SunOS) offer a library interface to
  805. the dynamic linker.
  806. In some systems this kind of interface is intended to replace the
  807. incremental loading functionality of the system linker.
  808. These dynamic linker interfaces usually come in the form of a library that
  809. exports functions such as \f2dlopen()\fP to map a shared object module or
  810. shared library into the address space of the caller (the base program)
  811. and \f2dlsym()\fP to obtain the address of a function or data item in
  812. the newly attached object module.
  813. .PP
  814. In some implementations, object files attached through \f2dlopen()\fP may
  815. directly reference symbols in the base program; in other implementations
  816. they may not.
  817. In any case, object files cannot directly reference symbols defined
  818. by objects that have been placed into the program by previous calls
  819. to \f2dlopen()\fP (only, if at all, indirectly by calling \f2dlsym()\fP).
  820. Thus, these dynamic linker interfaces are clearly inferior to
  821. incremental loading, as they lack the important capability to
  822. load a set of object files \f2incrementally\fP.
  823. Vendors who have replaced ``/bin/ld -A'' by a \f2dlopen\fP-style library
  824. in their UNIX systems, or who intend to do so, do not seem to be
  825. aware of the fact that this change will break applications that
  826. rely on incremental loading.
  827. .PP
  828. For \*E, the consequence of being restricted to dynamic linker
  829. interfaces of that kind is that, except for the simplest applications,
  830. one must pre-link all possible combinations of extensions that are
  831. not completely independent of each other.
  832. In general, given a set of \f2n\fP extensions each of which can be
  833. based on one out of \f2m\fP other extensions, this means having to prepare
  834. and keep around \f2n\|\(mu\|m\fP pre-linked object files; not to
  835. mention the contortions one has to go through when the hierarchy of
  836. extensions has a depth greater than two (not an unlikely scenario in
  837. practice).
  838. If the number of extensions and relations between them is larger than
  839. trivial, or if the extensions are large or require large libraries,
  840. keeping around all pre-linked combinations of object modules will
  841. waste a considerable amount of disk space.
  842. .PP
  843. Another, although minor, problem with these dynamic linker interfaces
  844. is that they usually offer only a simple-minded function (such as
  845. \f2dlsym()\fP) to look up the address of a specific symbol of a newly
  846. accessed object module (typically some kind of module initialization
  847. function); but they do not provide a way to scan all newly defined
  848. symbols.
  849. This functionality is insufficient to implement extension
  850. initialization in \*E, where a dynamically loadable extension often is
  851. composed from a number of small modules, each defining its own
  852. initialization function.
  853. Requiring a single, common initialization function name for the entire
  854. object file implies that (often configuration-dependent) ``glue code''
  855. must be added to call all the individual initialization functions,
  856. including the C++ static constructors.
  857. .P
  858. Non-Standard Language Features
  859. .PP
  860. As the current version of the Scheme standard (deliberately) does not
  861. specify several important language issues, such as error handling or
  862. syntactic extensions, we have added a number of non-standard language
  863. features to the Scheme interpreter of \*E to fill some of the holes.
  864. .PP
  865. A proposal for a macro extension has only recently been
  866. added as an addendum to the \f2Revised\u\s-1\|4\s0\d Report on the
  867. Algorithmic Language Scheme\fP [Clinger et al. 1991] and is still being
  868. discussed controversially within the Scheme community.
  869. To avoid having to wait for a final version of a macro system to
  870. evolve and be included in the Scheme standard, we implemented a
  871. simple-minded macro mechanism in \*E that resembles the macro
  872. facilities offered by various existing Scheme and Lisp systems.
  873. .PP
  874. One area where the Scheme standard does not specify any language
  875. features yet is error and exception handling; the standard merely
  876. states which error situations a conforming implementation is
  877. required to detect and report.
  878. Since it is essential for a non-trivial application to be able to
  879. gracefully handle error situations (such as failures in interactions
  880. with the operating system) and other exceptional conditions, we have
  881. added a simple error and exception handling facility to \*E.
  882. .PP
  883. When an error is detected by the interpreter, a user-supplied
  884. error handling procedure is invoked with arguments identifying the
  885. type and source of the error.
  886. The standard top-level of \*E provides a default error handler that
  887. prints an error message and then resumes the main read-eval-print loop
  888. by means of a \f2reset\fP primitive.
  889. Most primitives of \*E and the extensions use this error handling
  890. facility to signal an error, as opposed to indicating failure by
  891. a distinctive return value (which would be prone to being ignored).
  892. To by-pass the standard error handler and ``catch'' failure of
  893. a particular primitive, programs may enclose the call to the
  894. primitive by \f2call-with-current-continuation\fP and use
  895. \f2fluid-let\fP to dynamically bind the error handler to the
  896. continuation (as shown in listing @L(errset)).
  897. .Ls
  898. .Ss
  899. (define (new-open-input-file name)
  900.   (call-with-current-continuation
  901.     (lambda (return)
  902.       (fluid-let ((error-handler
  903.                     (lambda args (return #f))))
  904.         (open-input-file name)))))
  905. .Se
  906. .Lc "A version of open-input-file that returns the newly opened port \
  907. on success, #f on error"
  908. .Le errset
  909. .PP
  910. \*E provides a similar facility to handle an \f2interrupt\fP exception:
  911. a user-supplied interrupt handler is invoked when a SIGINT signal is sent
  912. to the interpreter (usually by typing the interrupt character on the
  913. keyboard).
  914. Support for other exceptions, such as timer interrupts, may be provided
  915. in future versions.
  916. .PP
  917. Another non-standard primitive that facilitates handling of errors is
  918. \f2dynamic-wind\fP, a generalization of the \f2unwind-protect\fP form
  919. offered by many Lisp dialects.
  920. \f2dynamic-wind\fP is used to implement the \f2fluid-let\fP special
  921. form (to create \f2fluid\fP or dynamic variable bindings).
  922. Both \f2dynamic-wind\fP and \f2fluid-let\fP are also provided by
  923. several other Scheme dialects [MIT 1984, Dybvig 1987].
  924. .PP
  925. The current version of the Scheme standard does not provide any
  926. language features that would make it possible to implement a useful
  927. Scheme debugger (apart from a debugger based on source code
  928. instrumentation).
  929. To compensate this shortcoming, we have added a few primitives that
  930. aid the implementation of a simple interactive debugger, among them an
  931. \f2eval\fP primitive (although, theoretically, \f2eval\fP could be
  932. implemented by writing an expression into a temporary file and then
  933. loading this file).
  934. In addition, \*E, like a few other Scheme dialects, provides lexical
  935. environments as first class (but immutable) objects.
  936. Other non-standard primitives that are helpful in debugging are
  937. \f2procedure-lambda\fP to obtain the lambda expression that evaluated
  938. to a given procedure, and a primitive that returns the list of
  939. currently active procedures together with their actual arguments and
  940. the lexical environments in which the procedure calls took place
  941. (a \f2backtrace\fP).
  942. .\"
  943. .\" provide, require; autoloading
  944. .P
  945. Garbage Collection
  946. .PP
  947. The garbage collector of \*E is based on the \f2stop-and-copy\fP
  948. algorithm; a description of this algorithm can be found, among
  949. other places, in [Abelson et al. 1985].
  950. An incremental, generational garbage collector for \*E has recently
  951. been adapted from Yip's garbage collector [Yip 1991] and is now being
  952. integrated into \*E as an alternative to the stop-and-copy garbage
  953. collector.
  954. .PP
  955. Extensions to \*E can register \f2before-GC\fP and \f2after-GC\fP
  956. functions with the interpreter; these functions are invoked by the
  957. garbage collector immediately before and after each garbage collection
  958. run.
  959. Within \f2after-GC\fP functions, extension can determine whether or not
  960. a particular Scheme object has been moved by the preceding garbage
  961. collection run.
  962. An object has not been moved by the garbage collector if no references
  963. to the object exist any longer, i.\|e.\& if it has become garbage.
  964. In this case, an extension may perform some kind of clean-up action;
  965. for example, if the now unreferenced object contains a handle to an open
  966. file, close this file.
  967. .PP
  968. The \*E distribution contains a library based on this mechanism that
  969. enables extensions to register a \f2termination function\fP for
  970. objects of a particular type.
  971. The termination function associated with an object is then invoked
  972. by the garbage collector automatically when this object has been
  973. detected to be unused.
  974. The Xlib extension of \*E uses this library to perform suitable
  975. finalization operations on objects created by the extensions, for
  976. example, close windows, unload fonts, and free colormap objects that
  977. have become unreferenced.
  978. This mechanism is slightly complicated by the fact that objects may
  979. have to be terminated in a predefined order; for instance, when an
  980. X11 display becomes garbage, all objects associated with this
  981. display must be terminated before the display itself is finally closed.
  982. .NH
  983. Practical Experiences with Elk
  984. .P
  985. Elk and ISOTEXT
  986. .PP
  987. In developing the ODA-based document processing system ISOTEXT, Elk
  988. proved to be a major asset [Bormann 1991].
  989. Scheme was used as the implementation language for all user interface
  990. aspects of ISOTEXT.
  991. Apart from providing extensibility to users of ISOTEXT, using Elk as
  992. the base for ISOTEXT made it possible to write the shell code in a high
  993. level language with all its amenities, e.\|g.\& automatic storage
  994. reclamation.
  995. As no recompilation and relinking is necessary, it is a quick operation
  996. to apply and test changes to the user interface.
  997. .PP
  998. Elk provides for a strong ``firewall'' in the ISOTEXT system:
  999. bugs in the Scheme code give rise to errors at the Scheme level, which can
  1000. easily be debugged using the (primitive, but functional) built-in
  1001. debugger of Elk, while conditions such as core dumps always are the
  1002. result of bugs in the ISOTEXT kernel implementation.
  1003. .PP
  1004. All this assistance for the development of ISOTEXT could be
  1005. achieved without sacrificing the performance of the ISOTEXT kernel
  1006. system, which is still written in efficient C++.
  1007. .PP
  1008. Elk also allowed to isolate the ISOTEXT kernel from the choice of an
  1009. X toolkit:
  1010. The ISOTEXT kernel is unaware of the toolkit being used (``Xt'' with
  1011. OSF/Motif).
  1012. The Scheme code builds a user interface using the Motif library
  1013. interface and provides X windows to the ISOTEXT kernel.
  1014. Input is processed by the Scheme code which calls editor primitives
  1015. provided by the ISOTEXT kernel and schedules redisplay operations.
  1016. Replacing Xt and OSF/Motif by e.\|g.\& \f2Xview\fP would require no
  1017. changes in the ISOTEXT kernel.
  1018. .PP
  1019. During the development of ISOTEXT it turned out that the extension
  1020. writer's interface of Elk could benefit from a number of improvements.
  1021. The main problem is that it is difficult to write non-trivial
  1022. extensions, because too much of the inner workings of the interpreter
  1023. is exposed to and must be dealt with by the extension writer.
  1024. .PP
  1025. In particular, as Elk can trigger a garbage collection run at any
  1026. time a chunk of heap space is requested, extensions must register
  1027. local or temporary Scheme object with the garbage collector to protect
  1028. them from being discarded during a subsequent GC run.
  1029. While this scheme has the advantage that maximum utilization of the
  1030. available heap space is guaranteed, it imposes a strict discipline
  1031. on the extension programmer.
  1032. Failure to properly protect temporary Scheme objects usually results
  1033. in delayed crashes of the application that hard to trace back to the
  1034. actual source of the problem.
  1035. In fact, when developing the X11 extensions to Elk, most of the time
  1036. spent for debugging was due to GC-related bugs.
  1037. .\"
  1038. .\"(cabo: recruiting problems)
  1039. .P 
  1040. Library Extensions
  1041. .PP
  1042. The problems we encountered when designing
  1043. and implementing Elk's interfaces to the C libraries of X11
  1044. are likely to be applicable to a wide range of similar APIs.
  1045. The X11 libraries, especially Xlib, are quite complex; the core Xlib
  1046. alone exports more than 600 functions and macros, within which
  1047. numerous different mechanisms are employed for passing arguments and
  1048. for manipulating objects, some of which are perceived to be rather
  1049. verbose and error-prone by many programmers.
  1050. This complexity is, at least partly, caused by the semantic
  1051. restrictiveness of the C programming language.
  1052. Thus, when designing the Scheme language interface, we had the
  1053. opportunity to eliminate some of the ``warts''.
  1054. .PP
  1055. If integration of a library with an extension language (or interactive
  1056. language in general) is not anticipated at the time the programmer's
  1057. interface of the library is designed, writing a properly functioning
  1058. extension language interface to this library can become quite difficult
  1059. or even impossible.
  1060. This problem is exemplified by the ``Xt'' toolkit intrinsics library
  1061. of X11, in particular by earlier versions of this library.
  1062. The following example illustrates a typical difficulty caused by
  1063. the ``static'' nature of the programmer's interface to ``Xt'':
  1064. .PP
  1065. Each class of graphical objects (\f2widgets\fP in ``Xt'' terminology)
  1066. exports a list of attributes (\f2resources\fP) that are associated with
  1067. objects of this class.
  1068. A function is provided by ``Xt'' to obtain the list of resources of a
  1069. widget class together with the name and C type (integer, string,
  1070. pixmap, color, etc.) of each resource.
  1071. On this basis, operations like setting the value of a widget's resource
  1072. from within Scheme can be implemented in a straightforward way.
  1073. The ``Xt'' extension just has to check if the user-supplied Scheme
  1074. value can be converted into a C object of the resource's type, perform
  1075. this conversion, and call the Xt-function to set the resource, or
  1076. complain to the user if the value is not suitable for this resource.
  1077. However, until recently, some classes of widgets had a subset of
  1078. resources (the \f2constraint resources\fP) whose names and types
  1079. could not be obtained by an ``Xt'' application.
  1080. While this omission is usually not perceived as a problem for C
  1081. programmers (who would know each widget's resources \f2a priori\fP from
  1082. reading the documentation), it had a dramatic effect on Elk's ``Xt''
  1083. extension, as now the knowledge about these resources had to be
  1084. hard-wired into the extension.
  1085. As a result, the extension's source code had to be modified for each
  1086. new widget set to be made usable from within Scheme code.
  1087. .PP
  1088. This particular problem has been remedied in recent releases of X11,
  1089. though several similar problems remain; even in the UNIX C library.
  1090. While design flaws of library interface often go unnoticed or are
  1091. considered minor when writing C or C++ programs (e.\|g.\& the fact
  1092. that implementations of the \f2qsort()\fP functions are
  1093. non-reentrant), they become crucial when these libraries are made
  1094. accessible to an extension language.
  1095. As the importance of extension languages is growing, it is essential
  1096. that future library interfaces will be designed with the particular
  1097. requirements of extensions languages in mind.
  1098. .PP
  1099. .\" automatic generation of interfaces / foreign functions
  1100. .P
  1101. Conclusions
  1102. .PP
  1103. Since the Elk project was started, both the research community and
  1104. significant industry projects have generated increasing numbers of
  1105. ``embeddable language'' implementations.
  1106. While many such languages inherit the syntactic flavor of BASIC, those
  1107. projects that focus on the ability to build non-trivial extensions
  1108. recently seem to almost exclusively turn to the Scheme language.
  1109. .PP
  1110. Scheme has proven to be an effective language for extension language
  1111. purposes.
  1112. In the beginning of the ISOTEXT project, there were concerns that an
  1113. implementation of the full Scheme language would be both too large and
  1114. too slow.
  1115. These reservations proved to be unfounded:
  1116. the code of Elk has less than half the size of medium size
  1117. applications such as \f2vi\fP.
  1118. While the performance of Elk may be uninspiring (no compiler is
  1119. available), this has proven not to be a critical issue, as any
  1120. bottlenecks can easily be replaced by a primitive recoded in C or C++.
  1121. .PP
  1122. While Elk has been used in the ISOTEXT project since 1987, legal
  1123. issues prevented making it publicly available until the fall of 1989.
  1124. Since, Elk has gained acceptance, in fact sufficient momentum to
  1125. encourage others to contribute software.
  1126. We know of projects that make use of Elk at research institutions such
  1127. as ... as well as in industry work at Autodesk, Computervision, 
  1128. HP, IBM, Intel, NEC, and SNI.
  1129. .P
  1130. Availability
  1131. .PP
  1132. Elk is available in legally unencumbered status.
  1133. The current version as of September 1992 is 1.5.
  1134. The newest version of Elk is available via anonymous FTP from
  1135. export.lcs.mit.edu (/contrib) and ftp.cs.tu-berlin.de (/pub).
  1136. .NH
  1137. References
  1138. .IP "[Abelson et al. 1985]
  1139. Harold Abelson and Gerald J. Sussman with Julie Sussman,
  1140. \f2Structure and Interpretation of Computer Programs\fP,
  1141. MIT Press, Cambridge, Mass., 1985.
  1142. .\"
  1143. .IP "[Bormann et. al. 1988]
  1144. Ute Bormann, Carsten Bormann, C. Bathe,
  1145. \f2SDE \- A WYSIWYG Editing and Formatting System for ODA and
  1146. SGML Documents\fP,
  1147. ESPRIT '88, Proceedings of the 5th Annual ESPRIT Conference,
  1148. Brussels, November 14-17, 1988.
  1149. .\"
  1150. .IP "[Bormann 1991]"
  1151. Carsten Bormann,
  1152. \f2Open Document Processing and the ISOTEXT System\fP,
  1153. Doctoral Dissertation, TU-Berlin, 1991.
  1154. .\"
  1155. .IP "[CFI 1991a]"
  1156. CAD Framework Initiative, CFI Extension Language Sub-Committee,
  1157. \f2CFI Extension Language Selection Document\fP,
  1158. CFI Document Number 87, CAD Framework Initiative Inc., Austin, Texas, 1991.
  1159. .\"
  1160. .IP "[CFI 1991b]"
  1161. CAD Framework Initiative, Extension Language Working Group:
  1162. Architecture Technical Sub-Committee,
  1163. \f2Extension Language: Core Language Selection\fP,
  1164. Draft Proposal Version 0.7, CFI Document Number ARCH-91-G-1,
  1165. CAD Framework Initiative Inc., Austin, Texas, 1991.
  1166. .\"
  1167. .IP "[Clinger et al. 1991]"
  1168. William Clinger and Jonathan Rees (Editors),
  1169. \f2Revised\u\s-1\|4\s0\d Report on the Algorithmic Language Scheme\fP,
  1170. November 2, 1991.
  1171. Available per FTP from altdorf.ai.mit.edu.
  1172. .\"
  1173. .IP "[CLX 1991]"
  1174. \f2CLX \- Common LISP X Interface\fP, 1991.
  1175. (Part of the X11 Release 5 distribution available from the
  1176. MIT software distribution center.)
  1177. .\"
  1178. .IP "[Dybvig 1987]"
  1179. R. Kent Dybvig,
  1180. \f2The Scheme Programming Language\fP,
  1181. Prentice Hall, Englewood Cliffs, NJ, 1987.
  1182. .\"
  1183. .IP "[Hansen 1990]"
  1184. Wilfred J. Hansen,
  1185. \f2Enhancing documents with embedded programs: How Ness extends
  1186. insets in the Andrew ToolKit\fP,
  1187. Proceedings of IEEE Computer Society 1990 International
  1188. Conference on Computer Languages,
  1189. March 12-15, 1990, New Orleans.
  1190. .\"
  1191. .IP "[IEEE\|Std\|1178-1990]"
  1192. \f2IEEE Standard for the Scheme Programming Language\fP,
  1193. New York, May 28, 1991.
  1194. .\"
  1195. .IP "[Joy 1980]"
  1196. Bill Joy,
  1197. \f2Changes in the VAX system in the Fourth Berkeley Distribution\fP,
  1198. Computer Systems Research Group,
  1199. University of California, Berkeley,
  1200. November 1980.
  1201. .\"
  1202. .IP "[Lewis et al. 1990]"
  1203. Bil Lewis, Dan LaLiberte, the GNU Manual Group,
  1204. \f2GNU Emacs Lisp Reference Manual\fP,
  1205. Edition 1.03, Free Software Foundation, Cambridge, Mass.,
  1206. December 1990.
  1207. .\"
  1208. .IP "[MIT 1984]"
  1209. \f2MIT Scheme Manual, Seventh Edition\fP,
  1210. Department of Electrical Engineering and Computer Science,
  1211. Massachusetts Institute of Technology,
  1212. Cambridge, Mass., September 1984.
  1213. .\"
  1214. .IP "[Ossanna 1979]"
  1215. J. F. Ossanna,
  1216. \f2Nroff/Troff User's Manual\fP,
  1217. UNIX Programmer's Manual, Seventh Edition, vol. 2,
  1218. Bell Telephone Laboratories, Murray Hill, NJ, January 1979.
  1219. .\"
  1220. .IP "[Ousterhout 1990]"
  1221. John K. Ousterhout,
  1222. \f2Tcl: An Embeddable Command Language\fP,
  1223. Proceedings of the USENIX 1990 Winter Conference,
  1224. January 1990, pp. 133-146.
  1225. .\"
  1226. .IP "[Scheifler et al. 1986]"
  1227. Robert W. Scheifler and Jim Gettys,
  1228. \f2The X Window System\fP,
  1229. ACM Transactions on Graphics, vol. 5, no. 2, pp. 79-109, 1986.
  1230. .\"
  1231. .IP "[Springer et al. 1989]"
  1232. George Springer and Daniel O. Friedman,
  1233. \f2Scheme and the Art of Programming\fP,
  1234. MIT Press, Cambridge, Mass., 1989.
  1235. .\"
  1236. .IP "[Stallman 1981]"
  1237. Richard M. Stallman,
  1238. \f2EMACS \- The Extensible, Customizable, Self-documenting Display
  1239. Editor Production System\fP,
  1240. SIGPLAN Notices, vol. 16, no. 6, pp. 147-156, Association for
  1241. Computing Machinery, New York, 1981.
  1242. .\"
  1243. .IP "[Yip 1991]"
  1244. G. May Yip,
  1245. \f2Incremental, Generational Mostly-Copying Garbage Collection in
  1246. Uncooperative Environments\fP,
  1247. WRL Research Report 91/8,
  1248. DEC Western Research Laboratory,
  1249. Palo Alto, California, 1991.
  1250. .bp
  1251. .SH
  1252. Appendix A:  Extending Elk \- An Example
  1253. .P
  1254. The ``ndbm'' Library Extension
  1255. .PP
  1256. The extensibility mechanisms of \*E can be demonstrated best by
  1257. a simple library extension.
  1258. Consider the \f2ndbm\fP library that is available on most versions
  1259. of UNIX.
  1260. This library implements functions to maintain a simple database
  1261. file of key/contents pairs.
  1262. .PP
  1263. As shown in Listing @L(ndbm), both the keys and the data to be stored
  1264. are described by the type \f2datum\fP; it consists of the data
  1265. (a string of bytes) and the length of the data.
  1266. \f2dbm_open()\fP opens a database file and returns a handle
  1267. to that file to be used in subsequent operations on that
  1268. database (a pointer to an opaque data type, similar to the \f2fopen\fP
  1269. and \f2readdir\fP interfaces); it returns a null pointer if the
  1270. file could not be opened.
  1271. A database is closed by a call to \f2dbm_close()\fP.
  1272. The data stored under a given key is accessed by the function
  1273. \f2dbm_fetch()\fP; it returns an object of type \f2datum\fP
  1274. (with a null \f2dptr\fP if the key could not be found).
  1275. \f2dbm_store\fP is used to insert an entry into a database and
  1276. to modify an existing entry; it returns zero on success and a
  1277. non-zero value on error.
  1278. .Ls
  1279. .Ss
  1280. #include <ndbm.h>
  1281. .Sl
  1282. .Sl
  1283. typedef struct {
  1284.     char *dptr;
  1285.     int dsize;
  1286. } datum;
  1287. .Sl
  1288. .Sl
  1289. DBM *dbm_open(char *file, int flags, int mode);
  1290. .Sl
  1291. void dbm_close(DBM *db);
  1292. .Sl
  1293. datum dbm_fetch(DBM *db, datum key);
  1294. .Sl
  1295. int dbm_store(DBM *db, datum key, datum data, int flags);
  1296. .Se
  1297. .Lc "The \f2ndbm\fP library"
  1298. .Ns
  1299. \f2Note:\fP For simplicity, several functions have been omitted.
  1300. .br
  1301. The \f2flags\fP and \f2mode\fP arguments of \f2dbm_open\fP are that
  1302. of the \f2open\fP system call.
  1303. The \f2flags\fP argument of \f2dbm_store\fP can be DBM_INSERT to
  1304. insert a new entry into the database or DBM_REPLACE to change
  1305. an existing entry.
  1306. .Ne
  1307. .Le ndbm
  1308. .PP
  1309. The straightforward way to write an \f2ndbm\fP extension to \*E is to
  1310. provide a new Scheme data type \f2dbm-file\fP together with the
  1311. obligatory type predicate \f2dbm-file?\fP and the Scheme primitive
  1312. procedures \f2dbm-open\fP, \f2dbm-close\fP, \f2dbm-fetch\fP and
  1313. \f2dbm-store\fP that operate on objects of type \f2dbm-file\fP.
  1314. .PP
  1315. \f2dbm-open\fP receives the filename (a string or a symbol);
  1316. the second argument is one of the symbols \f2reader\fP (open
  1317. the file read-only), \f2writer\fP (read and write access), and
  1318. \f2create\fP (read and write access, create new file if it does
  1319. not exist).
  1320. The optional filemode argument is an integer.
  1321. \f2dbm-open\fP returns an object of type \f2dbm-file\fP or #f
  1322. (false) if the file could not be opened.
  1323. \f2dbm-close\fP closes the database file associated with its
  1324. argument of type \f2dbm-file\fP.
  1325. It returns a non-printing object.
  1326. .PP
  1327. \f2dbm-fetch\fP expects a \f2dbm-file\fP and a string argument
  1328. (the key to be searched) and returns a string (the data stored
  1329. under the key) or #f if the key does not exist.
  1330. Note that in \*E strings may contain arbitrary 8-bit characters,
  1331. including the null byte.
  1332. \f2dbm-store\fP is called with a \f2dbm-file\fP, two strings
  1333. (key and data) and one of the symbols \f2insert\fP and \f2replace\fP.
  1334. Its integer return value is the return value of \f2dbm_store()\fP.
  1335. .PP
  1336. These procedures and the new \f2dbm-file\fP type can be used
  1337. by application programmers to manipulate database files
  1338. in those parts of their applications that are written in Scheme.
  1339. Listing @L(ndbm-example) shows a small example.
  1340. .Ls
  1341. .Ss
  1342. (define expand-mail-alias
  1343.   (lambda (alias)
  1344.     (let ((d (dbm-open "/etc/aliases" 'reader)))
  1345.       (if (not d)
  1346.           (error 'expand-mail-alias "cannot open database"))
  1347.     (unwind-protect
  1348.       (dbm-fetch d alias)
  1349.       (dbm-close d)))))
  1350. .Sl
  1351. (define address-of-staff (expand-mail-alias "staff"))
  1352. .Se
  1353. .Lc "Using the ndbm extension"
  1354. .Ns
  1355. \f2Note:\fP The \f2unwind-protect\fP and the \f2error\fP form
  1356. are not present in standard Scheme.
  1357. .Ne
  1358. .Le ndbm-example
  1359. .P
  1360. The Anatomy of a Scheme Type
  1361. .PP
  1362. Listing @L(ndbm-skeleton) shows the part of the extension that deals with
  1363. the new data type \f2dbm-file\fP and the extension initialization
  1364. function.
  1365. The variable \f2T_Dbm\fP will hold the unique identifier of the
  1366. newly defined type.
  1367. The structure \f2S_Dbm\fP defines the C representation of the type;
  1368. one such C structure is declared for each composite Scheme type.
  1369. Its main component is the handle of the database file that is
  1370. contained in each object of type \f2dbm-file\fP.
  1371. .Ls
  1372. .Ss
  1373. #include <scheme.h>
  1374. #include <ndbm.h>
  1375. .Sl
  1376. int T_Dbm;
  1377. .Sl
  1378. struct S_Dbm {
  1379.     DBM *dbm;
  1380.     char alive;   /* 0 or 1 */
  1381. };
  1382. .Sl
  1383. #define DBMF(obj) ((struct S_Dbm *)POINTER(obj))
  1384. .Sl
  1385. int Dbm_Equal(a, b) Object a, b; {
  1386.     return DBMF(a)->alive && DBMF(b)->alive && DBMF(a)->dbm == DBMF(b)->dbm;
  1387. }
  1388. .Sl
  1389. void Dbm_Print(d, port) Object d, port; {
  1390.     Printf(port, "#[dbm-file %lu]", DBMF(d)->dbm);
  1391. }
  1392. .Sl
  1393. Object P_Is_Dbm(x) Object x; {
  1394.     return TYPE(x) == T_Dbm ? True : False;
  1395. }
  1396. .Sl
  1397. void init_dbm() {
  1398.     Define_Primitive(P_Is_Dbm,    "dbm-file?", 1, 1, EVAL);
  1399.     Define_Primitive(P_Dbm_Open,  "dbm-open",  2, 3, VARARGS);
  1400.     Define_Primitive(P_Dbm_Close, "dbm-close", 1, 1, EVAL);
  1401.     Define_Primitive(P_Dbm_Store, "dbm-store", 4, 4, EVAL);
  1402.     Define_Primitive(P_Dbm_Fetch, "dbm-fetch", 2, 2, EVAL);
  1403. .Sl
  1404.     T_Dbm = Define_Type("dbm-file", sizeof(struct S_Dbm),
  1405.         Dbm_Equal, Dbm_Equal, Dbm_Print, NOFUNC);
  1406. }
  1407. .Se
  1408. .Lc "Skeleton of the ndbm extension"
  1409. .Ns
  1410. \f2Note:\fP For simplicity some details have been omitted in this
  1411. listing, and the calling interface of some functions has been
  1412. simplified; the program would not compile in this form.
  1413. A working \f2gdbm\fP (GNU dbm) extension is included in the \*E
  1414. distribution.
  1415. .Ne
  1416. .Le ndbm-skeleton
  1417. .PP
  1418. Scheme objects can usually live longer than their underlying
  1419. C objects.
  1420. In case of the \f2dbm-file\fP type, a Scheme object of that type
  1421. can apparently still be used after its database handle has been
  1422. closed by a call to \f2dbm-close\fP.
  1423. As \*E extensions must not crash the application, we must prevent
  1424. such stale objects from being used in further calls to
  1425. \f2dbm-fetch\fP, \f2dbm-store\fP, and \f2dbm-close\fP.
  1426. One way to achieve this is to record in each Scheme object whether
  1427. the underlying C object is still alive or has been terminated.
  1428. The boolean component \f2alive\fP in the \f2dbm-file\fP type
  1429. serves this purpose.
  1430. It is initialized with true and is set to false in \f2dbm-close\fP.
  1431. Further operations on objects with \f2alive\fP being false are
  1432. rejected.
  1433. .PP
  1434. The interpreter stores all Scheme objects in variables of type
  1435. \f2Object\fP.
  1436. An \f2Object\fP is typically a 32-bit value; it is composed of
  1437. a \f2tag\fP part and a \f2pointer\fP part.
  1438. The \f2tag\fP part indicates the type of the object, and the remaining
  1439. bits hold the actual memory address of the object (they point into
  1440. the interpreter's heap).
  1441. The macros \f2TYPE\fP and \f2POINTER\fP are provided to extract
  1442. the fields of an \f2Object\fP.
  1443. Each type definition must define a macro to extract the object's
  1444. memory address from an \f2Object\fP (by means of \f2POINTER\fP) 
  1445. and then cast it into a pointer to the underlying C structure
  1446. (see \f2#define DBMF\fP in Listing @L(ndbm-skeleton)).
  1447. .PP
  1448. \f2Dbm_Equal()\fP implements both the \f2eqv?\fP and the \f2equal?\fP
  1449. predicates for \f2dbm-file\fP objects; it returns true if both objects
  1450. being compared are alive and contain identical \f2DBM\fP handles.
  1451. .PP
  1452. \f2Dbm_Print()\fP is called by the interpreter each time an object
  1453. of type \f2dbm-file\fP is to be printed; it is invoked with the
  1454. object and the Scheme port to which the output is to be sent.
  1455. .PP
  1456. \f2P_Is_Dbm()\fP implements the primitive procedure \f2dbm-file?\fP
  1457. (the type predicate).
  1458. As with all primitives, it receives arguments of type \f2Object\fP and
  1459. returns an \f2Object\fP, and it has a name beginning with ``P_''.
  1460. .PP
  1461. The definition of the initialization function \f2init_dbm()\fP
  1462. is straightforward; it invokes \f2Define_Primitive()\fP once
  1463. for each primitive procedure and finally \f2Define_Type()\fP to
  1464. make the new type known to the interpreter.
  1465. .P
  1466. Primitive Procedures \- The Details
  1467. .PP
  1468. Listing @L(dbm-open) gives the definitions of the primitives \f2dbm-open\fP
  1469. and \f2dbm-close\fP.
  1470. .Ls
  1471. .Ss
  1472. static SYMDESCR Flag_Syms[] = {
  1473.     { "reader", O_RDONLY },
  1474.     { "writer", O_RDWR },
  1475.     { "create", O_RDWR|O_CREAT },
  1476.     { 0, 0 }
  1477. };
  1478. .Sl
  1479. Object P_Dbm_Open(argc, argv) int argc; Object *argv; {
  1480.     char *p;
  1481.     DBM *dp;
  1482.     Object d;
  1483. .Sl
  1484.     Make_C_String(argv[0], p);
  1485.     dp = dbm_open(p, Symbols_To_Bits(argv[1], 0, Flag_Syms),
  1486.         argc == 3 ? Get_Integer(argv[2]) : 0644);
  1487.     if (dp == 0)
  1488.         return False;
  1489.     d = Alloc_Object(sizeof(struct S_Dbm), T_Dbm, 0);
  1490.     DBMF(d)->dbm = dp;
  1491.     DBMF(d)->alive = 1;
  1492.     return d;
  1493. }
  1494. .Sl
  1495. void Check_Dbm(d) Object d; {
  1496.     Check_Type(d, T_Dbm);
  1497.     if (!DBMF(d)->alive)
  1498.         Primitive_Error("invalid dbm-file: ~s", d);
  1499. }
  1500. .Sl
  1501. Object P_Dbm_Close(d) Object d; {
  1502.     Check_Dbm(d);
  1503.     DBMF(d)->alive = 0;
  1504.     dbm_close(DBMF(d)->dbm);
  1505.     return Void;
  1506. }
  1507. .Se
  1508. .Lc "ndbm extension \- implementation of \f2dbm-open\fP and \f2dbm-close\fP
  1509. .Le dbm-open
  1510. .PP
  1511. \f2dbm-open\fP, as it has an optional argument, is a function
  1512. with \f2VARARGS\fP calling discipline (not to be confused with the
  1513. C language feature of the same name).
  1514. This is indicated by the last argument to the corresponding call
  1515. to \f2Define_Primitive\fP in the extension initialization.
  1516. Primitives of this type receive an array of \f2Objects\fP and
  1517. a count.
  1518. .PP
  1519. The initial call to the macro \f2Make_C_String\fP checks if the
  1520. first argument to \f2dbm-open\fP is a string (or a symbol) and
  1521. converts it to a C string.
  1522. To obtain the second argument to \f2dbm_open()\fP, the symbol
  1523. passed to the Scheme primitive (\f2reader\fP, \f2writer\fP, etc.)
  1524. has to be mapped to a corresponding flags combination (\f2O_RDONLY\fP,
  1525. \f2O_RDWR\fP, etc.).
  1526. This is accomplished by the function \f2Symbols_To_Bits()\fP; it
  1527. is invoked with a Scheme symbol, a flag indicating whether a single
  1528. symbol or a list of symbols (a mask) is to be converted, and a
  1529. table of pairs of symbol names and C integers.
  1530. The third argument to \f2dbm_open\fP is the filemode;
  1531. \f2Get_Integer()\fP converts a Scheme number to a C integer.
  1532. \f2dbm-open\fP finally allocates a new Scheme object of type \f2T_Dbm\fP
  1533. on the heap, initializes the components of the object, and returns it.
  1534. .PP
  1535. The auxiliary function \f2Check_Dbm()\fP is used by the remaining
  1536. primitives to check whether a given object is of type \f2dbm-file\fP
  1537. and if so, whether it is stale.
  1538. In this case an error is signaled; \f2Primitive_Error()\fP enters
  1539. the error handler of \*E.
  1540. .PP
  1541. \f2P_Dbm_Close()\fP just marks the object as stale by setting
  1542. \f2alive\fP to false and closes the database file.
  1543. .PP
  1544. Listing @L(dbm-store) shows the implementation of \f2dbm-store\fP and
  1545. \f2dbm-fetch\fP.
  1546. \f2Make_Integer()\fP is the pendant to \f2Get_Integer()\fP;
  1547. it converts a C integer into a Scheme number.
  1548. Likewise, \f2Make_String()\fP converts a C string into a
  1549. Scheme string.
  1550. .bp
  1551. .Ls
  1552. .Ss
  1553. static SYMDESCR Store_Syms[] = {
  1554.     { "insert",  DBM_INSERT },
  1555.     { "replace", DBM_REPLACE },
  1556.     { 0, 0 }
  1557. };
  1558. .Sl
  1559. Object P_Dbm_Store(d, key, content, flag) Object d, key, content, flag; {
  1560.     datum k, c;
  1561.     int result;
  1562. .Sl
  1563.     Check_Dbm(d);
  1564.     Check_Type(key, T_String);
  1565.     Check_Type(content, T_String);
  1566.     k.dptr = STRING(key)->data;       k.dsize = STRING(key)->size;
  1567.     c.dptr = STRING(content)->data;   c.dsize = STRING(content)->size;
  1568.     result = dbm_store(DBMF(d)->dbm, k, c,
  1569.         Symbols_To_Bits(flag, 0, Store_Syms));
  1570.     return Make_Integer(result);
  1571. }
  1572. .Sl
  1573. Object P_Dbm_Fetch(d, key) Object d, key; {
  1574.     datum k, c;
  1575. .Sl
  1576.     Check_Dbm(d);
  1577.     Check_Type(key, T_String);
  1578.     k.dptr = STRING(key)->data;       k.dsize = STRING(key)->size;
  1579.     c = dbm_fetch(DBMF(d)->dbm, k);
  1580.     return c.dptr ? Make_String(c.dptr, c.dsize) : False;
  1581. }
  1582. .Se
  1583. .Lc "ndbm extension \- implementation of \f2dbm-store\fP and \f2dbm-fetch\fP
  1584. .Le dbm-store
  1585. .\" ----------
  1586. .\" Erwaehnen: Little Languages
  1587. .\" ----------
  1588. .\" Read the CFI papers again
  1589.